package http_utils

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"time"
	Beans "tuowei.com/pkg/sing/beans"
	"tuowei.com/pkg/sing/sign_service"
	Tools "tuowei.com/pkg/sing/utils"
	"tuowei.com/pkg/xlog"
)

func pretty(obj interface{}) {
	bts, _ := json.MarshalIndent(obj, "", " ")
	fmt.Println(string(bts))
}

func init() {
	sign_service.EsignInitService()
}
func SendHttp(apiUrl string, data string, method string, headers map[string]string) ([]byte, int) {
	// API接口返回值
	var apiResult []byte
	url := apiUrl
	var jsonStr = []byte(data)
	var req *http.Request
	var err error
	if method == "GET" || method == "DELETE" {
		req, err = http.NewRequest(method, url, nil)
	} else {
		req, err = http.NewRequest(method, url, bytes.NewBuffer(jsonStr))
	}
	for k, v := range headers {
		req.Header.Set(k, v)
	}
	client := &http.Client{}
	resp, err := client.Do(req)

	if err != nil {
		panic(err)
	} else {
		var httpStatus = resp.StatusCode
		if httpStatus != http.StatusOK {
			return apiResult, httpStatus
		}
		defer resp.Body.Close()
		body, _ := ioutil.ReadAll(resp.Body)
		apiResult = body
		return apiResult, httpStatus
	}

}

//文件上传
func UpLoadFile(uploadUrl string, filePath string, contentMD5 string, contentType string) string {

	//Beans.InstaneEsignInitConfig().Host()+
	//创建一个缓冲区对象,后面的要上传的body都存在这个缓冲区里
	bodyBuf := &bytes.Buffer{}
	//要上传的文件
	//创建第一个需要上传的文件,filepath.Base获取文件的名称
	//打开文件
	fd1, _ := os.Open(filePath)
	defer fd1.Close()
	//把第一个文件流写入到缓冲区里去
	_, _ = io.Copy(bodyBuf, fd1)
	//获取请求Content-Type类型,后面有用
	//contentType := bodyWriter.FormDataContentType()
	//创建一个http客户端请求对象
	client := &http.Client{}
	//创建一个post请求
	req, _ := http.NewRequest("PUT", uploadUrl, nil)
	//设置请求头
	req.Header.Set("Content-MD5", contentMD5)
	//这里的Content-Type值就是上面contentType的值
	req.Header.Set("Content-Type", contentType)
	req.Header.Set("X-Tsign-Open-App-Id", Beans.InstaneEsignInitConfig().ProjectId())
	req.Header.Set("X-Tsign-Open-Auth-Mode", "Signature")
	timestamp := strconv.Itoa(int(time.Now().UnixMilli()))
	req.Header.Set("X-Tsign-Open-Ca-Timestamp", timestamp)
	req.Header.Set("Accept", "*")
	req.Header.Set("Date", "")
	//
	md5Str := Tools.DohashMd5("")

	message := Tools.AppendSignDataString("PUT", "*/*", md5Str, contentType, "", "", uploadUrl)
	//
	reqSignature := Tools.DoSignatureBase64(message, Beans.InstaneEsignInitConfig().ProjectScert())
	req.Header.Set("X-Tsign-Open-Ca-Signature", reqSignature)

	//转换类型
	req.Body = ioutil.NopCloser(bodyBuf)
	//发送数据
	data, err := client.Do(req)
	if err != nil {
		fmt.Println("err=", err.Error())
	}
	//读取请求返回的数据
	bytes, _ := ioutil.ReadAll(data.Body)
	defer data.Body.Close()
	//返回数据
	return string(bytes)
}

func SendCommHttp(apiUrl string, dataJsonStr string, method string) (initResult []byte, httpStatus int) {
	httpUrl := Beans.InstaneEsignInitConfig().Host() + apiUrl
	var md5Str string
	md5Str = Tools.DohashMd5(dataJsonStr)
	message := Tools.AppendSignDataString("POST", "*/*", md5Str, "application/json; charset=UTF-8", "", "", apiUrl)
	reqSignature := Tools.DoSignatureBase64(message, Beans.InstaneEsignInitConfig().ProjectScert())
	// 初始化接口返回值
	initResult, httpStatus = SendHttp(httpUrl, dataJsonStr, method, buildCommHeader(md5Str, reqSignature))
	xlog.Infof("请求e签地址:%s,请求参数:%s", apiUrl, dataJsonStr)
	xlog.Infof("请求e签结果:%s", string(initResult))
	return initResult, httpStatus
}

func buildCommHeader(contentMD5 string, reqSignature string) (header map[string]string) {
	headers := map[string]string{}
	headers["X-Tsign-Open-App-Id"] = Beans.InstaneEsignInitConfig().ProjectId()
	headers["X-Tsign-Open-Ca-Timestamp"] = strconv.FormatInt(time.Now().UnixNano()/1e6, 10)
	headers["Accept"] = "*/*"
	headers["X-Tsign-Open-Ca-Signature"] = reqSignature
	headers["Content-MD5"] = contentMD5
	headers["Content-Type"] = "application/json; charset=UTF-8"
	headers["X-Tsign-Open-Auth-Mode"] = "Signature"
	return headers
}

//

//CheckFileStatus 检测文件状态
//fileId 上传到e签的返回的文件id
// 注意:此处返回的json如果需要返给前端或自己使用，不要直接用json.mashal,因为&符号会被转义
func CheckFileStatus(fileId string) (Beans.CheckFilStatusRsp, error) {
	//rsp := new(Beans.CheckFilStatusRsp)
	byts, httpStatus := SendCommHttp(fmt.Sprintf("/v3/files/%s", fileId), "", http.MethodGet)
	rsp := Beans.CheckFilStatusRsp{}
	if httpStatus != http.StatusOK {
		return rsp, errors.New("服务器网络出错")
	}
	json.Unmarshal(byts, &rsp)
	if rsp.Data.FileStatus != 2 && rsp.Data.FileStatus != 5 {
		return rsp, errors.New("文件状态不对")
	}
	return rsp, nil

}

func GetTemplateDetail(docTemplateId string) (Beans.GetTemplateDetailRsp, error) {
	rsp := Beans.GetTemplateDetailRsp{}
	url := fmt.Sprintf("/v3/doc-templates/%s", docTemplateId)
	byts, httpStatus := SendCommHttp(url, "", http.MethodGet)
	if httpStatus != http.StatusOK {
		return rsp, errors.New("e签服务器网络出错")
	}
	json.Unmarshal(byts, &rsp)
	if rsp.Code != 0 {
		return rsp, errors.New(rsp.Message)
	}
	return rsp, nil
}

func FillTemplate(request Beans.FillTemplateRequest) (*Beans.FillTemplateRsp, error) {
	var jsonStr string
	rsp := new(Beans.FillTemplateRsp)
	if data, err := json.Marshal(request); err == nil {
		jsonStr = string(data)
	}
	bts, httpStatus := SendCommHttp("/v3/files/create-by-doc-template", jsonStr, http.MethodPost)
	if httpStatus != http.StatusOK {
		return rsp, errors.New("e签服务器网络出错")
	}
	json.Unmarshal(bts, rsp)
	return rsp, nil
}

//https://esignoss.esign.cn/1111564182/5f87b490-1147-4749-9014-443048cb0178/2b5d1fc4-66c7-4d75-be23-822d5a92837e.pdf?Expires=1662227928\u0026OSSAccessKeyId=LTAI4G23YViiKnxTC28ygQzF\u0026Signature=%2FIO%2B487C27pz6LKZ361V5FkZWg8%3D
//https://esignoss.esign.cn/1111564182/5f87b490-1147-4749-9014-443048cb0178/2b5d1fc4-66c7-4d75-be23-822d5a92837e.pdf?Expires=1662228012\u0026OSSAccessKeyId=LTAI4G23YViiKnxTC28ygQzF\u0026Signature=AA%2BJ9JBUQFlNRUSDWSX0xGbfzN8%3D
